package net.viservice.mysql.backup;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class DataBaseBackupJob implements Job {

	private static final Logger logger = LoggerFactory.getLogger(PrintTimeJob.class);
	private final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
		Date currentDate = new Date();
		String currentTime = sdf.format(currentDate);

		JobKey jobKey = context.getJobDetail().getKey();
		JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();

		logger.info(jobKey.toString() + " DataBaseBackupJob执行时间" + currentTime + ",fireTime" + context.getFireTime());
		logger.info("开始执行备份");

		String backupFileRootPath = jobDataMap.getString("backupFileRootPath") + "/database";
		String backupFilePath = backupFileRootPath + "/" + new SimpleDateFormat("yyyy-MM-dd-HHmm").format(currentDate);
		File backupFileDir = new File(backupFilePath);
		if (!backupFileDir.exists()) {
			backupFileDir.mkdirs();
		}

		String backupFileName = new SimpleDateFormat("yyyyMMddHHmmss").format(currentDate) + (new Random().nextInt(99) + 10) + ".sql";
		try {
			String mysqlRootPath = jobDataMap.getString("mysqlRootPath");
			String mysqlUser = jobDataMap.getString("mysqlUser");
			String mysqlPassword = jobDataMap.getString("mysqlPassword");
			String[] databases = jobDataMap.getString("databaseName").split(",");
			for (String databaseName : databases) {
				executeBackupScript(backupFilePath, databaseName, backupFileName, mysqlRootPath, mysqlUser, mysqlPassword);
			}
			Thread.sleep(30 * 1000);// 等待备份文件的存储
			logger.info("备份成功！");
		} catch (Exception e) {
			logger.error("备份失败！备份过程中发生异常:", e);
		} finally {
			logger.info("执行备份结束");
		}

		Integer history = jobDataMap.getIntValue("history");
		deleteHistoryBackupFile(backupFileRootPath, history);

	}

	private void executeBackupScript(String backupFilePath, String databaseName, String backupFileName, String mysqlRootPath, String mysqlUser, String mysqlPassword) throws IOException, InterruptedException {
		String targertFilePath = backupFilePath + "/" + databaseName + "#" + backupFileName;

		String str = "\"" + mysqlRootPath + "/mysqldump\" -u" + mysqlUser + " -p" + mysqlPassword + " " + databaseName + " > " + targertFilePath;

		logger.error(str);

		String osName = System.getProperty("os.name");
		if (osName.toLowerCase().substring(0, 3).equals("win")) {
			Process process = java.lang.Runtime.getRuntime().exec(new String[] { "cmd", "/c", str });
			int exitValue = process.waitFor();

			logger.info("backup success! target file:" + targertFilePath + ",exitValue:" + exitValue);
			process.getOutputStream().close();
		} else {
			java.lang.Runtime.getRuntime().exec(new String[] { "sh", "-c", str });
			logger.info("backup success! target file:" + targertFilePath);
		}
	}

	/**
	 * 删除历史备份文件
	 */
	private void deleteHistoryBackupFile(String backupFileRootPath, Integer history) {
		File backupFile = new File(backupFileRootPath);
		if (backupFile.exists() && backupFile.isDirectory()) {
			File childFile[] = backupFile.listFiles();// 顺序已经是按照日期排好的了。
			if (childFile.length > history) {
				int deleteFileSize = (childFile.length - history);// 要删除的文件数
				for (int i = 0; i < deleteFileSize; i++) {
					if (childFile[i].isFile()) {
						childFile[i].delete();
					} else {
						deleteDir(childFile[i]);
					}
					logger.info("deleteHistoryBackupFile " + childFile[i] + " 。");
				}
			}
		}
	}

	/**
	 * 删除空目录
	 * 
	 * @param dir
	 *            将要删除的目录路径
	 */
	private void doDeleteEmptyDir(String dir) {
		boolean success = (new File(dir)).delete();
		if (success) {
			System.out.println("Successfully deleted empty directory: " + dir);
		} else {
			System.out.println("Failed to delete empty directory: " + dir);
		}
	}
	
	/**
	 * 递归删除目录下的所有文件及子目录下所有文件
	 * 
	 * @param dir
	 *            将要删除的文件目录
	 * @return boolean Returns "true" if all deletions were successful. If a
	 *         deletion fails, the method stops attempting to delete and returns
	 *         "false".
	 */
	private boolean deleteDir(File dir) {
		if (dir.isDirectory()) {
			String[] children = dir.list();
			// 递归删除目录中的子目录下
			for (int i = 0; i < children.length; i++) {
				boolean success = deleteDir(new File(dir, children[i]));
				if (!success) {
					return false;
				}
			}
		}
		// 目录此时为空，可以删除
		return dir.delete();
	}

}
